header {package metamodel.parser;}
class TraversalLexer extends Lexer;
    options {k=4;}
    tokens{
        AS = "as";
	    COLLECTION = "collection";
	    CASE =       "switch";
	    TYPEREF= 	 "reference";
	    IMPORT =     "import";
    }
    WS: (' '|'\t'){$setType(Token.SKIP);};
    NEWLINE:("\r\n"| '\r'| '\n')
		{
			newline();
			$setType(Token.SKIP);
		};

    IDENTIFIER: (('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9'|'$')+);
	
    LPAREN: ('(');
    RPAREN: (')');
    COMMA:(',');
    COLON:(':');
    SEMI:(';');
    DOT:('.');
    STAR:('*');
    
    COMMENT_1
        : "/*"
		   ( options { generateAmbigWarnings=false; }
		   :	{ LA(2) != '/' }? '*'
		   |	'\r' '\n'		{newline();}
		   |	'\r'			{newline();}
		   |	'\n'			{newline();}
           |   ~('*' | '\n' | '\r')
		   )*
          "*/"
		{$setType(Token.SKIP);}
	;



{import java.util.*;
 import metamodel.*;

 }
class TraversalParser extends Parser;

options {
            k=4;
        }


qualifiedIdentifier returns [String qualifiedIdentifier]
    {qualifiedIdentifier = null;}
    : (first:IDENTIFIER {qualifiedIdentifier=first.getText();})
      (DOT rest:IDENTIFIER {qualifiedIdentifier=qualifiedIdentifier +"."+ rest.getText();})*;


property returns [Property property]
  {String type;
   ClassNode classNode;
   property=null;
  }

: (id:IDENTIFIER COLON   (classNode=classNode
                                     {property=new ObjectReference(id.getText(), classNode);}
                          |   COLLECTION^ LPAREN! classNode=classNode RPAREN!
                                     {property=new CollectionRef(id.getText(), classNode);}
                          |   type=qualifiedIdentifier
                                     {property=new FlatProperty(id.getText(),type);}
                          )
   )   |  (fid:IDENTIFIER
                                     {property=new FlatProperty(fid.getText(),"java.lang.Object");}
          )
;

propertylist returns [List<Property> list]
    {
        Property property,property1;
        list=new java.util.LinkedList<Property>();
    }
    :  (property1=property {list.add(property1);
                          }
                  (COMMA property=property {list.add(property);})*)?
  ;

classNode returns [ClassNode classNode]
    {
        String type;
        List<Property> propertyList=null;
        classNode=null;
        ClassNode typecase;
        ClassNode typeref;
    }
    : type = qualifiedIdentifier (AS id:IDENTIFIER )? LPAREN propertyList=propertylist RPAREN
        {classNode=new ClassNode(type,propertyList);
         if (id!=null)
         	classNode.setLabel(id.getText());
         }
        |
       typecase=typecase{
         classNode=typecase;
       }
       |
       typeref=typeref{
         classNode=typeref;
       }

    ;


classList returns [List list]
    {
        ClassNode firstNode, classNode;
        list=new java.util.LinkedList();
    }
    :  firstNode=classNode {list.add(firstNode);
                      }
                  (COMMA classNode=classNode {list.add(classNode);})*
  ;

typeref returns [TypeReference ref]{
           ref=null;
           String path;
  }
  : TYPEREF LPAREN labelRef:IDENTIFIER RPAREN
               {ref=new TypeReference(labelRef.getText());}
;


typecase returns [PolyClassNode classNode]{
                String type;
                List subClasses = null;
                classNode=null;
             }
    : CASE LPAREN type=qualifiedIdentifier RPAREN (AS id:IDENTIFIER )? LPAREN subClasses=classList RPAREN
        { classNode=new PolyClassNode(type,subClasses); 
          if (id!=null)
          	classNode.setLabel(id.getText());
        }
 ;

importDeclaration returns [ClassResolver resolver]
{resolver = null;
 List<ClassResolver> imports;}
: IMPORT LPAREN  imports = importList RPAREN {
    resolver = new ChainedResolver(imports);
};

importList returns [List<ClassResolver> resolvers]
{resolvers = new ArrayList<ClassResolver>();
ClassResolver first, rest;}
:((first = importItem{resolvers.add(first);})(COMMA rest = importItem {resolvers.add(rest);})*)?
;

importItem returns [ClassResolver resolver]
{resolver = null;
 String exactImport, wildcardImport;}
: (exactImport = qualifiedIdentifier   { resolver = new ExactClassResolver(exactImport);} )
  (DOT STAR {resolver = new PrefixClassResolver(exactImport); })?
;

traversalDescription returns [ClassNode model] {
  ClassResolver resolver = null;
  model = null;
}
: (resolver = importDeclaration)?
  model = classNode
{model.setResolver(resolver);}
;




